package com.kinyx.framework.data;

import java.util.ArrayList;
import java.util.HashMap;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kinyx.framework.annotation.assist.CanNotNull;
import com.kinyx.framework.annotation.assist.CanNull;
import com.kinyx.framework.annotation.assist.ReturnNotNull;
import com.kinyx.framework.annotation.assist.ReturnNull;
import com.kinyx.framework.annotation.assist.Tester;
import com.kinyx.framework.annotation.assist.Throws;
import com.kinyx.framework.utils.KStringUtils;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

/**
 * JSON工具类
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class KJsonUtils4Jackson extends KObjectMapper {

	/**
	 * 初始化Mapper对象
	 * @return Mapper对象
	 */
	@ReturnNotNull
	private static ObjectMapper mapper() {
		return Configs4Jackson.ObjectMapperFactory.jsonMapper();
	}

	/**
	 * 判断字符串是否为JSON字符串
	 * @param json JSON字符串
	 * @return true：是JSON字符串；false：不是JSON字符串；
	 */
	@ReturnNotNull
	static boolean isJson(@CanNull final String json) {
		if (KStringUtils.isBlank(json)) { return false; }
		try {
			mapper().readTree(json);
			return true;
		} catch (final JsonProcessingException e) {
			return false;
		}
	}

	/**
	 * JSON字符串转XML字符串
	 * @param json JSON字符串
	 * @param nullable true: 允许null值; false: 不允许null值;
	 * @param isArray true: 数组; false: 对象;
	 * @return XML字符串
	 */
	@ReturnNull("json == null && nullable == true")
	@Throws(at = "KObjectMapper.toHashMap(ObjectMapper, String)", value = "JsonMappingException", when = "ObjectMapper.readValue(String, JavaType)")
	@Throws(at = "KObjectMapper.toHashMap(ObjectMapper, String)", value = "JsonProcessingException", when = "ObjectMapper.readValue(String, JavaType)")
	@Throws(at = "KObjectMapper.writeValueAsString(ObjectMapper, Object)", value = "JsonProcessingException", when = "ObjectMapper.writeValueAsString(Object)")
	static String toXml(@CanNull final String json, @CanNotNull final boolean nullable, @CanNotNull final boolean isArray) {
		if (KStringUtils.isBlank(json)) { return nullable ? null : ""; }
		if (json.equals("{}") || json.equals("[]")) { return ""; }
		return KXmlUtils.toXml(toHashMap(json), nullable, isArray);
	}

	/**
	 * 对象转JSON字符串
	 * @param obj 待转换对象
	 * @param nullable true: 允许null值; false: 不允许null值;
	 * @param isArray true: 数组; false: 对象;
	 * @return JSON字符串
	 */
	@ReturnNull("obj == null && nullable == true")
	@Throws(at = "KObjectMapper.writeValueAsString(ObjectMapper, Object)", value = "JsonProcessingException", when = "ObjectMapper.writeValueAsString(Object)")
	@Tester("com.kinyx.framework.data.KJsonUtils_Tester_toJson")
	static String toJson(@CanNull final Object obj, @CanNotNull final boolean nullable, @CanNotNull final boolean isArray) {
		if (obj == null) { return defaultValue(false, nullable, isArray); }
		return writeValueAsString(mapper(), obj);
	}

	/**
	 * JSON字符串转对象
	 * @param <T> 泛型
	 * @param json JSON字符串
	 * @param clazz 对象类型
	 * @return 对象
	 */
	@ReturnNull("KStringUtils.isBlank(json)")
	@Throws(at = "KObjectMapper.toBean(ObjectMapper, String, Class)", value = "JsonMappingException", when = "ObjectMapper.readValue(String, Class)")
	@Throws(at = "KObjectMapper.toBean(ObjectMapper, String, Class)", value = "JsonProcessingException", when = "ObjectMapper.readValue(String, Class)")
	static <T> T toBean(@CanNull final String json, @CanNotNull final Class<T> clazz) {
		return KStringUtils.isBlank(json) ? null : toBean(mapper(), json, clazz);
	}

	/**
	 * JSON字符串转HashMap对象
	 * @param json JSON字符串
	 * @return HashMap对象
	 */
	@ReturnNull("KStringUtils.isBlank(json)")
	@Throws(at = "KObjectMapper.toHashMap(ObjectMapper, String)", value = "JsonMappingException", when = "ObjectMapper.readValue(String, JavaType)")
	@Throws(at = "KObjectMapper.toHashMap(ObjectMapper, String)", value = "JsonProcessingException", when = "ObjectMapper.readValue(String, JavaType)")
	static HashMap<String, String> toHashMap(@CanNull final String json) {
		return KStringUtils.isBlank(json) ? null : toHashMap(mapper(), json);
	}

	/**
	 * JSON字符串转ArrayList对象
	 * @param <T> 泛型
	 * @param json JSON字符串
	 * @param clazz 类
	 * @return ArrayList对象
	 */
	@ReturnNull("KStringUtils.isBlank(json)")
	@Throws(at = "KObjectMapper.toArrayList(ObjectMapper, String, Class)", value = "JsonMappingException", when = "ObjectMapper.readValue(String, JavaType)")
	@Throws(at = "KObjectMapper.toArrayList(ObjectMapper, String, Class)", value = "JsonProcessingException", when = "ObjectMapper.readValue(String, JavaType)")
	static <T> ArrayList<T> toArrayList(@CanNull final String json, @CanNotNull final Class<T> clazz) {
		return KStringUtils.isBlank(json) ? null : toArrayList(mapper(), json, clazz);
	}

	/**
	 * JSON字符串转换JsonNode对象
	 * @param json JSON字符串
	 * @return JsonNode对象
	 */
	@ReturnNull("KStringUtils.isBlank(json)")
	@Throws(at = "KObjectMapper.toJsonNode(ObjectMapper, String)", value = "JsonMappingException", when = "ObjectMapper.readTree(String)")
	@Throws(at = "KObjectMapper.toJsonNode(ObjectMapper, String)", value = "JsonProcessingException", when = "ObjectMapper.readTree(String)")
	public static JsonNode toJsonNode(@CanNull final String json) {
		return KStringUtils.isBlank(json) ? null : toJsonNode(mapper(), json);
	}

	/**
	 * 深层取JsonNode对象
	 * @param json JSON字符串
	 * @param keys 键数组
	 * @return JsonNode对象
	 */
	@ReturnNull("KStringUtils.isBlank(json)")
	@Throws(at = "KObjectMapper.deepGet(ObjectMapper, String, String...)", value = "JsonMappingException", when = "ObjectMapper.readTree(String)")
	@Throws(at = "KObjectMapper.deepGet(ObjectMapper, String, String...)", value = "JsonProcessingException", when = "ObjectMapper.readTree(String)")
	public static JsonNode deepGet(@CanNull final String json, @CanNull final String... keys) {
		return KStringUtils.isBlank(json) ? null : deepGet(mapper(), json, keys);
	}

}
